#include <QPainter>
#include <QtDebug>

#include "SudokuGraphicsCellDelegate.h"
#include "SudokuCellEditor.h"
#include "SudokuDataModel.h"
#include "SudokuCellValidator.h"

/**
  * Font for candidates
  */
static const QFont cCandidateFont("Courier", 10);
/**
  * Font for values
  */
static const QFont cValueFont("Arial", 20);

static const QPen cCellFramePen(QBrush(Qt::black), 1);

static const QPen cBoxFramePen(QBrush(Qt::blue), 2);

static const QPen cCandidatePen(QBrush(Qt::black), 1);


SudokuGraphicsCellDelegate::SudokuGraphicsCellDelegate(QObject* parent) : QStyledItemDelegate(parent),
    mValidator(new SudokuCellValidator(this))
{ 
}

QWidget* SudokuGraphicsCellDelegate::createEditor ( QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index ) const
{
    Q_UNUSED(option);
    SudokuCellEditor* cellEditor = new SudokuCellEditor(index.data().toString(), parent);

    const SudokuDataModel* model = static_cast<const SudokuDataModel*>(index.model());
    int sudokuSize = model->getSudokuData()->getSize();

    mValidator->setTop(sudokuSize);
    cellEditor->setValidator(mValidator);

    //TODO make cursor invisible
    return cellEditor;
}

void SudokuGraphicsCellDelegate::setEditorData(QWidget *editor,
                                    const QModelIndex &index) const
{
    QString value = index.model()->data(index, Qt::EditRole).toString();
    SudokuCellEditor* lineEdit = static_cast<SudokuCellEditor*>(editor);
    lineEdit->setText(value);
}

void SudokuGraphicsCellDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
                                   const QModelIndex &index) const
{
    SudokuCellEditor* lineEdit = static_cast<SudokuCellEditor*>(editor);
    QString value = lineEdit->text();
    qDebug() << "SudokuGraphicsCellDelegate::setModelData value=" << value;
    model->setData(index, value, Qt::EditRole);
}

void SudokuGraphicsCellDelegate::updateEditorGeometry(QWidget *editor,
    const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
{
    editor->setGeometry(option.rect.adjusted(-1,-1,1,1));
}

void SudokuGraphicsCellDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
                                       const QModelIndex &index) const
{
    //QStyledItemDelegate::paint(painter, option, index);
    // qDebug() <<  "SudokuGraphicsCellDelegate::paint" << index.data().toString();

    painter->save();

    const SudokuDataModel* model = static_cast<const SudokuDataModel*>(index.model());

    int sudokuSizeBox = model->getSudokuData()->getSizeBox();
    SudokuCell* currentCell = model->getSudokuData()->cellAt(index.row(), index.column());

    painter->setPen(cCellFramePen);
    painter->drawRect(option.rect);//.adjusted(2,2,-2,-2)
    //if(option.state & QStyle::State_HasFocus)
    //    painter->drawRect(option.rect.adjusted(2,2,-2,-2));

    //if(option.state & QStyle::State_MouseOver)
    //    painter->drawRect(option.rect.adjusted(4,4,-4,-4));

    //if(option.state & QStyle::State_Selected)
    //   painter->drawRect(option.rect.adjusted(6,6,-6,-6));

    //painter->drawLine(1,1,10,30);

    painter->setPen(cBoxFramePen);

    QRect cellRect = option.rect;//.adjusted(1,1,-1,-1);

    if(currentCell->isLeftInBox())
    {
        painter->drawLine(cellRect.topLeft(), cellRect.bottomLeft());
    }

    if(currentCell->isTopInBox())
    {
        painter->drawLine(cellRect.topLeft(), cellRect.topRight());
    }

    if(currentCell->isRightInBox())
    {
        painter->drawLine(cellRect.topRight(), cellRect.bottomRight());
    }

    if(currentCell->isBottomInBox())
    {
        painter->drawLine(cellRect.bottomLeft(), cellRect.bottomRight());
    }

    if(currentCell->isEmpty())
    {
        painter->setFont(cCandidateFont);

        float candidateRectHeight = cellRect.height()/sudokuSizeBox;
        float candidateRectWidth = cellRect.width()/sudokuSizeBox;

        QRectF candidateRect(cellRect.left(), cellRect.top(), candidateRectWidth, candidateRectHeight);

        for(int dx=0;dx<sudokuSizeBox;++dx)
        {
            for(int dy=0;dy<sudokuSizeBox;++dy)
            {
                QRectF currentCandidateRect = candidateRect.translated(dx * candidateRectWidth, dy * candidateRectHeight);

                int currentCandidateIndex = dx + dy * sudokuSizeBox;
                if(currentCell->getPossibl(currentCandidateIndex))
                {
                    QString currentCandidateValue = QString::number(currentCandidateIndex+1);
                    painter->setPen(cCandidatePen);
                    painter->drawText(currentCandidateRect, Qt::AlignCenter, currentCandidateValue);
                }
                else
                {
                    QColor color;
                    bool shouldPaint = true;

                    switch (currentCell->getEliminateMethod(currentCandidateIndex))
                    {
                    case LockedCandidatesPointing:
                        color = QColor(255, 0, 0, 100);
                        break;
                    case LockedCandidatesClaiming:
                        color = QColor(0, 255, 0, 100);
                        break;
                    case NakedSubsets:
                        color = QColor(0, 0, 255, 100);
                        break;
                    case HiddenSubsets:
                        color = QColor(255, 0, 255, 100);
                        break;
                    case Xwing:
                        color = QColor(255, 255, 0, 200);
                        break;
                    case Elimination:
                        shouldPaint = true;
                        color = QColor(0, 255, 255, 100);
                        break;
                    case Empty:
                        shouldPaint = false;
                        color = QColor(Qt::white);
                        break;
                    case Unknown:
                        color = QColor(255, 0, 0, 255);
                        break;
                    default:
                        color = QColor(0, 0, 0, 100);
                        break;
                    }

                    if(shouldPaint)
                    {
                        //TODO optimize painting
                        painter->setRenderHint(QPainter::Antialiasing, true);

                        /*double xEllipse = sqrt(currentCandidateRect.width()*(sqrt(2)-1))/2;
                        double yEllipse = sqrt(currentCandidateRect.height()*(sqrt(2)-1))/2;

                        QLinearGradient gradient(currentCandidateRect.topLeft().x() + xEllipse,
                                                 currentCandidateRect.topLeft().y() + yEllipse,
                                                 currentCandidateRect.bottomRight().x() - xEllipse,
                                                 currentCandidateRect.bottomRight().y() - yEllipse);*/

                        QLinearGradient gradient(currentCandidateRect.topLeft(), currentCandidateRect.bottomRight());
                        gradient.setColorAt(0, Qt::white);
                        gradient.setColorAt(1, color);


                        QBrush brush(gradient);

                        painter->setBrush(brush);
                        painter->setPen(color);
                        painter->drawEllipse(currentCandidateRect.adjusted(1,1,-1,-1));
                        painter->setRenderHint(QPainter::Antialiasing, false);
                    }

                }
            }
        }

    }
    else
    {
        QColor color;
        switch(currentCell->getPrior())
        {
        case NakedSingles:
            color = QColor(Qt::green);
            break;
        case HiddenSingles:
            color = QColor(0,0,200);
            break;
        case Given:
            color = QColor(Qt::darkGray);
            break;
        default:
            color = QColor(Qt::black);
            break;
        }

        painter->setPen(QPen(QBrush(color), 1));
        painter->setFont(cValueFont);
        painter->drawText(option.rect, Qt::AlignCenter, index.data().toString());
    }

    painter->restore();

}
